package com.movisol.messenger.views;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager.LayoutParams;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

import com.movisol.c2dm.controllers.C2DMController;
import com.movisol.c2dm.events.PushNotificationReceivedEvent;
import com.movisol.c2dm.ilisteners.IPushNotificationReceived;
import com.movisol.messenger.R;
import com.movisol.messenger.controllers.MessengerController;
import com.movisol.messenger.helper.MessengerHelper;
import com.movisol.messenger.views.controls.Bubble;
import com.movisol.messenger.views.controls.ChatMessageDate;
import com.movisol.messenger.views.controls.ContactRow;
import com.movisol.messengercommunicator.data.Contact;
import com.movisol.messengercommunicator.data.Conversation;
import com.movisol.messengercommunicator.data.Message;
import com.movisol.messengercommunicator.events.DataLoadedEvent;
import com.movisol.messengercommunicator.helper.MessengerCommunicatorHelper;
import com.movisol.messengercommunicator.ilisteners.IMessagePosted;
import com.movisol.messengercommunicator.ilisteners.IMessagesListLoaded;
import com.movisol.messengerprofileservice.data.UserProfile;
import com.movisol.messengerprofileservice.helpers.MessengerProfileHelper;
import com.movisol.tools.HelperUtils;

public class Chat extends Activity implements IMessagesListLoaded, IMessagePosted, OnClickListener, IPushNotificationReceived{
	
	private final MessengerController mc = MessengerController.getInstance();
	private Context context;
	private String conversationId;
	private String lastMessage;
	private LinearLayout messagesLayout;
	private LinearLayout bottomLayoutChat;
	private EditText chatEditText;
	private Button sendButton;
	private Integer sequenceNumber;
	private HashMap<String, Integer> localMessageList; //Contains the local messages wrote in this session
	private Handler timer;
	private Runnable r = null;
	private ScrollView scv;
	private boolean timerStarted = false;
	private Date lastDateAdded = new Date(0);
	private boolean scrollToBottom = false;
	private final C2DMController c2dmController = C2DMController.getInstance();
	private Conversation currentConversation;
	private float scale;
	private int maxWidth;
	private boolean showContact = false;
	private AlertDialog contactsAlertDialog = null;
	private HashMap<String, Integer> colorMap = null;
	private final List<Integer> colors = new ArrayList<Integer>();
	private Boolean pushReceived = false;
	private static final long WAIT_TIME_TO_REQUEST = 5000;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);		
		setContentView(R.layout.chat);
		getWindow().setFormat(PixelFormat.RGBA_8888);
		getWindow().addFlags(LayoutParams.FLAG_DITHER);
		mc.setCurrentPage(MessengerController.CHAT_PAGE);

		context = mc.getContext();
		
		colorMap = new HashMap<String, Integer>();

		scale = context.getResources().getDisplayMetrics().density;
		maxWidth = HelperUtils.dpToPixels(Integer.valueOf(HelperUtils.getConfigParam("MAX_WIDTH_MESSAGE_DP", context)),
				scale);

		sequenceNumber = 0;
		if(mc.getCurrentConversation() != null)
			try { //Avoid to mix the conversations when a push is received
				currentConversation = mc.getCurrentConversation().duplicate();
			} catch (CloneNotSupportedException e) {
				e.printStackTrace();
			}
		
		localMessageList = new HashMap<String, Integer>();

		//Initializes the Graphical User Interface
		initializeGUI();
		
		//Sets the listeners 
		mc.cc.addMessagesListLoadedListener(this);
		mc.cc.addMessagePostedListener(this);
		
		//Add myself to the participant list
		Contact me = new Contact();
		me.setContactId(mc.pc.getUserProfile().getUserId());
		me.setEmail(mc.pc.getUserProfile().getEmail());
		me.setName(mc.pc.getUserProfile().getCalculatedNickName());
		//Put me in the first position
		currentConversation.getContacts().add(0, me);

		// Color configuration
		Integer integerColor = null;
		String color;
		int i = 1;
		while ((color = HelperUtils.getConfigParam("Color" + i++, context)) != null) {
			integerColor = MessengerHelper.parseColor(color);
			colors.add(integerColor);
		}

		int colorNumber = 0;
		for (Contact contact : currentConversation.getContacts()) {
			if (colorNumber >= colors.size())
				colorNumber = 1;
			colorMap.put(contact.getContactId(), colors.get(colorNumber++));
		}
		
		// Check if this instantiation comes from a push
		if (getIntent().getExtras() != null)
			pushReceived = getIntent().getExtras().getBoolean("pushReceived");

		//If the conversation already exists then load the messages of it
		if(currentConversation != null && currentConversation.getConversationId() != null)
		{
			mc.loadMessagesList();
			
			conversationId = currentConversation.getConversationId();
			lastMessage = currentConversation.getLastMessage();
		}
		else
		{
			bottomLayoutChat.setVisibility(View.VISIBLE);
		}
		
		c2dmController.setContext(context);
		c2dmController.addPushNotificationsListener(this);
		
	}
	

	@Override
	protected void onNewIntent(Intent intent) {
		super.onNewIntent(intent);
		
		localMessageList.clear();
		messagesLayout.removeAllViews();
		updateMessagesList();
		pushReceived = true;
	}



	@Override
	protected void onPause() {
		super.onPause();
	}


	@Override
	protected void onStop() {
		super.onStop();
		if (!showContact)
			if (!isFinishing())
				finish();
	}


	@Override
	protected void onDestroy() {
		super.onDestroy();
		
		//Remove the listeners in order disconnect the chat from the advises
		mc.cc.removeMessagesListLoadedListener(this);
		mc.cc.removeMessagePostedListener(this);
		mc.setCurrentConversation(null);
		
		if (timer != null)
			timer.removeCallbacks(r, null);
		timer = null;
		r = null;
		timerStarted = false;
	}
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		if (requestCode == 1) {
			showContact = false;
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {

		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.chat_menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle item selection
		switch (item.getItemId()) {
		case R.id.view_contacts:
			showContacts();
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}


	private void showContacts() {

		if (contactsAlertDialog == null)
		{
			AlertDialog.Builder builder = new AlertDialog.Builder(this);

			String infService = Context.LAYOUT_INFLATER_SERVICE;
			LayoutInflater li = (LayoutInflater) context.getSystemService(infService);

			LinearLayout container = null;
			container = (LinearLayout) li.inflate(R.layout.showcontacts, container, true);

			// HorizontalScrollView hsv = (HorizontalScrollView)
			// findViewById(R.id.showContactsHorizontalScroll);

			// hsv.setForegroundGravity(Gravity.CENTER_HORIZONTAL);

			LinearLayout showContactsLayout = (LinearLayout) ((HorizontalScrollView) container.getChildAt(0))
					.getChildAt(0);
			showContactsLayout.removeAllViews();
			int padding = HelperUtils.dpToPixels(2, scale);
			UserProfile up = null;

			for (Contact chatContacto : currentConversation.getContacts()) {
				/* Just add the contacts in the conversation, but not myself */
				if (!chatContacto.getContactId().equals(mc.pc.getUserProfile().getUserId())) {
					// Set the chatContacto Profile by default
					up = new UserProfile();
					up.setEmail(chatContacto.getEmail());
					Drawable picture = context.getResources().getDrawable(R.drawable.img_unknown).mutate();

					// Look for the contact of the chat in our friend list
					for (ContactRow miContacto : mc.getApprovedContactList())
						if (miContacto.getFriend().getUserProfile().getUserId().equals(chatContacto.getContactId())) {
							up = miContacto.getFriend().getUserProfile();
							picture = miContacto.getImageContactRow().getDrawable();
							break;
						}

					// Contact's profile image
					ImageView image = new ImageView(context);
					image.setImageDrawable(picture);
					int size = HelperUtils.dpToPixels(60, scale);
					image.setLayoutParams(new ViewGroup.LayoutParams(size, size));
					image.setPadding(padding, 0, padding, 0);
					image.setTag(up);
					image.setOnClickListener(this);

					LinearLayout tmpLayout = new LinearLayout(context);
					tmpLayout.setOrientation(LinearLayout.VERTICAL);
					tmpLayout.setGravity(Gravity.CENTER);
					tmpLayout.addView(image);
					tmpLayout.setPadding(padding, 0, padding, 0);

					// Contact's name
					TextView tvName = new TextView(context);
					tvName.setText(up.getCalculatedNickName());
					tvName.setTextSize(10);
					tvName.setPadding(0, 2, 0, 0);
					tvName.setGravity(Gravity.CENTER);

					tmpLayout.addView(tvName);
					showContactsLayout.addView(tmpLayout);
				}

			}


			// hsv.addView(ll);
			builder.setCancelable(true).setView(container);
			contactsAlertDialog = builder.create();
		}


		contactsAlertDialog.show();

	}

	private void initializeGUI() {

		chatEditText = (EditText) findViewById(R.id.chatEditText);
		sendButton = (Button) findViewById(R.id.sendButton);
		scv = (ScrollView) findViewById(R.id.scrollView1);
		messagesLayout = (LinearLayout) findViewById(R.id.messagesLayout);
		bottomLayoutChat = (LinearLayout) findViewById(R.id.bottomLayoutChat);
		
		sendButton.setOnClickListener(this);
		
		messagesLayout.removeAllViews();

        
//        getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
		
	}
	
    public void timerStart()
    {
   	
    	if(!timerStarted)
    	{
    		timerStarted = true;
			timer = new Handler() {

				@Override
				public void handleMessage(android.os.Message msg) {
					super.handleMessage(msg);
					mc.loadMessagesList();

				}

			};
    		    		
    		//Hide the soft keyboard (Does it works?)
    		InputMethodManager in = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            in.hideSoftInputFromWindow(chatEditText.getApplicationWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS);
            
            //It was originally INVISIBLE to avoid soft keyboard to be shown
			// bottomLayoutChat.setVisibility(View.VISIBLE);
            
    	}
    	
    }

	@Override
	public void messagesListLoaded(DataLoadedEvent evt) {
		if(evt.getError() == null)
		{
			updateMessagesList();
			// bottomLayoutChat.setVisibility(View.VISIBLE);
			//Start the timer, refreshing every WAIT_TIME_TO_REQUEST ms
			timerStart();
			if (timer != null)
				timer.sendEmptyMessageDelayed(0, WAIT_TIME_TO_REQUEST);
		}
		else
		{
			HelperUtils.LogE(getClass(), evt.getError());
			HelperUtils.showToastMessage(context, evt.getError(), Toast.LENGTH_LONG);
			finish();
		}
		
	}

	@Override
	public void onClick(final View v) {

		if(v.getId() == R.id.sendButton)
		{
			if(chatEditText.getText() != null)
			{
				String message = chatEditText.getText().toString();
				if(!message.equals(""))
				{
					sequenceNumber++;

					Date now = new Date();
					//Check the current time to add or not a new Message Date					
					ChatMessageDate cmd = checkLastDateAdded(now);
					if (cmd != null)
						messagesLayout.addView(cmd);

					Bubble bubble = new Bubble(context, message, maxWidth, true, "Me", now, colorMap.get(mc.pc
							.getUserProfile().getUserId()));
					messagesLayout.addView(bubble);
					
					// Refresh the conversations of the conversation page
					// obtaining the last message
					mc.cc.updateConversationInConversationList(conversationId, message);

					chatEditText.setText(null);

					//Prepare the Message to send
					Message msg = new Message();
					msg.setBody(message);
					msg.setSequenceNumber(sequenceNumber);
					msg.setDateCreated(new Date());
					
					if(conversationId != null)
					{
						// msg.setContacts(currentConversation.getContacts());
						msg.setConversationId(conversationId);
					}
					else
					{
						conversationId = MessengerProfileHelper.generateSignature( MessengerCommunicatorHelper.generateConversationId(currentConversation.getContacts()) + HelperUtils.getConfigParam("ChatSecretPhrase", context));
						currentConversation.setConversationId(conversationId);
						List<Contact> tmpContact = new ArrayList<Contact>();
						for (Contact contact : currentConversation.getContacts()) {
							Contact tmp = new Contact();
							tmp.setContactId(contact.getContactId());
							tmpContact.add(tmp);
						}
						msg.setContacts(tmpContact);
						//Add the new created conversation to our conversation list, then next time we enter, the conversation could be loaded
						mc.cc.getConversationsList().getConversations().add(currentConversation);
					}
					
					//Post
					mc.postMessage(msg);
					//Forces the scroll-view to scroll to bottom 
					scrollToBottom();
				}
			}
			
		}
		
		if (v instanceof ImageView) {
			showContact = true;
			v.setBackgroundColor(Color.RED);
			mc.pc.setTmpUserProfile((UserProfile) v.getTag());
			Intent profileIntent = new Intent(this, ProfilePage.class);
			profileIntent.putExtra("unknowContact", true);

			for (ContactRow miContacto : mc.getApprovedContactList())
				if (mc.pc.getTmpUserProfile().getEmail().equals(miContacto.getFriend().getUserProfile().getEmail())) {
					profileIntent.putExtra("unknowContact", false);
					break;
				}

			startActivityForResult(profileIntent, 1);
			if (contactsAlertDialog != null)
				contactsAlertDialog.dismiss();
			v.postDelayed(new Runnable() {
				
				@Override
				public void run() {
					v.setBackgroundColor(Color.TRANSPARENT);
					
				}
			}, 1000);
		}

	}
	
	private ChatMessageDate checkLastDateAdded(Date date) {
		
		//Add a layout with the current date of the messages. One per day
		if(date.getTime() > lastDateAdded.getTime())
		{
			lastDateAdded = new Date(date.getTime());
			lastDateAdded.setHours(23);
			lastDateAdded.setMinutes(59);
			lastDateAdded.setSeconds(59);
			ChatMessageDate chatDateMessage = new ChatMessageDate(context, lastDateAdded);
			return chatDateMessage;
			// messagesLayout.addView(chatDateMessage);
		}
		return null;
		
	}

	private void scrollToBottom()
	{
		scv.post(new Runnable() {
			
			@Override
			public void run() {
				scv.fullScroll(View.FOCUS_DOWN);
				
			}
		});
	}

	
	@Override
	public void messagePosted(DataLoadedEvent evt) {
		
		if(evt.getError() == null)
		{
			//Add the last messagePublicId of the last message wrote to our local message list
			localMessageList.put(mc.cc.getMessageAnswered().getMessages().get(0).getMessagePublicId(), mc.cc.getMessageAnswered().getMessages().get(0).getSequenceNumber());

		} else {
			HelperUtils.LogE(getClass(), evt.getError());
			HelperUtils.showToastMessage(context, evt.getError(), Toast.LENGTH_SHORT);
		}
		
	}
	
	private class AsyncUpdateMessagesList extends AsyncTask<Void, Void, Void> {

		List<View> viewsToAdd = new ArrayList<View>();
		int contacts = 0;
		@Override
		protected Void doInBackground(Void... params) {
			String lastMessage = null;

			if (mc.cc.getMessagesList() != null && mc.cc.getMessagesList().getMessages().size() > 0) {


				// Trick to avoid old fired listeners to get into the
				// current conversation
				for (Contact contact : mc.cc.getMessagesList().getContacts())
					for (Contact contact2 : currentConversation.getContacts())
						if (contact.getContactId().equals(contact2.getContactId()))
							contacts++;

				if (contacts == mc.cc.getMessagesList().getContacts().size()) {
					for (Message msg : mc.cc.getMessagesList().getMessages())
						/* If we don't have it locally, then add it */
						if (localMessageList.get(msg.getMessagePublicId()) == null) {
							ChatMessageDate cmd = checkLastDateAdded(msg.getDateCreated());
							if (cmd != null)
								viewsToAdd.add(cmd);
		
							boolean right = false;

							String friendName;
							if (msg.getContactId().equals(mc.pc.getUserProfile().getUserId())) {
								friendName = "Me";
								right = true;
							} else
								friendName = MessengerHelper.getNameById(currentConversation.getContacts(),
										msg.getContactId());

							Bubble bubble = new Bubble(context, msg.getBody(), maxWidth, right, friendName,
									msg.getDateCreated(), colorMap.get(msg.getContactId()));

							viewsToAdd.add(bubble);
							// messagesLayout.addView(bubble);

							// Forces the scrollview to scroll to bottom
							scrollToBottom = true;
							localMessageList.put(msg.getMessagePublicId(), -1);

							lastMessage = msg.getBody();
						}

					if (pushReceived) {
						mc.cc.updateConversationInConversationList(conversationId, lastMessage);
						pushReceived = false;
					}
				}

			}
			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			if (contacts == mc.cc.getMessagesList().getContacts().size()) {
				for (View view : viewsToAdd) {
					messagesLayout.addView(view instanceof Bubble ? (Bubble) view : (ChatMessageDate) view);
				}
			}

			if (scrollToBottom) {
				scrollToBottom();
				scrollToBottom = false;
			}
			bottomLayoutChat.setVisibility(View.VISIBLE);
		}

	}

	private void updateMessagesList() {

		new AsyncUpdateMessagesList().execute();

		
	}

	public String getConversationId() {
		return conversationId;
	}

	public void setConversationId(String conversationId) {
		this.conversationId = conversationId;
	}


	public String getLastMessage() {
		return lastMessage;
	}


	public void setLastMessage(String lastMessage) {
		this.lastMessage = lastMessage;
	}


	@Override
	public void pushNotificationReceived(PushNotificationReceivedEvent evt) {
		pushReceived = true;
		mc.loadMessagesList();

	}
	

}
